Ccay.UI.XCalendar = {};
﻿/**@description Xcalendar 组件*/
( function ( Calendar ) {
	var currLang=Ccay.Local.getCurrLanguage(),
    I18N=( {
		zh_CN:{
			_SDN : ["日","一","二","三","四","五","六"],
			_MN  : ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
			_SMN : ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
			_Today : "今天",
			_GoToday :"跳至今天",
			_PreY  :"上一年",
			_NextY :"下一年",
			_PreM  :"上一月",
			_NextM :"下一月",
			_Close :"关闭",
			_Click :"（CTRL-）点击改变值",
			_Select:"选择日期",
			_SelectMonth:"选择月份",
			_Time  :"时间:"
		},
		en_US:{
			_SDN : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
			_MN  : ["January","February","March","April","May","June","July","August","September","October","November","December"],
			_SMN : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
			_Today : "Today",
			_GoToday :"Go today",
			_PreY  :"Prev. year",
			_NextY :"Next year",
			_PreM  :"Prev. month",
			_NextM :"Next month",
			_Close :"Close",
			_Click :"( CTRL- )Click to change value",
			_Select:"Select date",
			_SelectMonth:"Select Month",
			_Time  :"Time:"
		}
	} )[currLang]||{
		_SDN : [$i18n("Ccay.Calendar.SDN.Sun"),$i18n("Ccay.Calendar.SDN.Mon"),$i18n("Ccay.Calendar.SDN.Tue"),$i18n("Ccay.Calendar.SDN.Wed"),$i18n("Ccay.Calendar.SDN.Thu"),$i18n("Ccay.Calendar.SDN.Fri"),$i18n("Ccay.Calendar.SDN.Sat")],
		_MN  : [$i18n("Ccay.Calendar.MN.January"),$i18n("Ccay.Calendar.MN.February"),$i18n("Ccay.Calendar.MN.March"),$i18n("Ccay.Calendar.MN.April"),$i18n("Ccay.Calendar.MN.May"),$i18n("Ccay.Calendar.MN.June"),$i18n("Ccay.Calendar.MN.July"),$i18n("Ccay.Calendar.MN.August"),$i18n("Ccay.Calendar.MN.September"),$i18n("Ccay.Calendar.MN.October"),$i18n("Ccay.Calendar.MN.November"),$i18n("Ccay.Calendar.MN.December")],
		_SMN : [$i18n("Ccay.Calendar.SMN.Jan"),$i18n("Ccay.Calendar.SMN.Feb"),$i18n("Ccay.Calendar.SMN.Mar"),$i18n("Ccay.Calendar.SMN.Apr"),$i18n("Ccay.Calendar.SMN.May"),$i18n("Ccay.Calendar.SMN.Jun"),$i18n("Ccay.Calendar.SMN.Jul"),$i18n("Ccay.Calendar.SMN.Aug"),$i18n("Ccay.Calendar.SMN.Sep"),$i18n("Ccay.Calendar.SMN.Oct"),$i18n("Ccay.Calendar.SMN.Nov"),$i18n("Ccay.Calendar.SMN.Dec")],
		_Today : $i18n("Ccay.Calendar.Button.Today"),
		_GoToday :$i18n("Ccay.Calendar.Button.GoToday"),
		_PreY  :$i18n("Ccay.Calendar.Button.PrevYear"),
		_NextY :$i18n("Ccay.Calendar.Button.NextYear"),
		_PreM  :$i18n("Ccay.Calendar.Button.PrevMonth"),
		_NextM :$i18n("Ccay.Calendar.Button.NextMonth"),
		_Close :$i18n("Ccay.Calendar.Button.Close"),
		_Click :$i18n("Ccay.Calendar.Button.ClickChangeValue"),
		_Select:$i18n("Ccay.Calendar.Button.SelectDate"),
		_SelectMonth:$i18n("Ccay.Calendar.Button.SelectMonth"),
		_Time  :$i18n("Ccay.Calendar.Time.Time")
	},

	templ = ['<div class="calendar ccay-popup ccay-calendar" active=false id="ccay_calendar_div" onselectstart="return false;"><table class="current"><thead> <tr>',
				'<td class=button navtype=300></td> <td class="button title" colspan="5"  navtype=300 ></td>',
				'<td class=button ttip="', I18N._Close, '" navtype=200><div>×</div></td></tr>',
				'<tr class="headrow"><td class="button nav" navtype="-2" ttip="', I18N._PreY, '"> <div>«</div></td>',
				'<td class="button nav"  navtype="-1" ttip="', I18N._PreM, '"><div>‹</div> </td>',
				'<td class="button" id="btnToday"    style="min-width:30px"    navtype="0"  colspan=3 ttip="', I18N._GoToday, '"><div>', I18N._Today, '</div> </td>',
				'<td class="button nav"  navtype="1" ttip="', I18N._NextM, '"><div>›</div> </td>',
				'<td class="button nav"  navtype="2" ttip="', I18N._NextY, '"> <div>»</div></td></tr>',
				'<tr class="daynames"><td class="day name weekend">', I18N._SDN[0], '</td><td class="day name">', I18N._SDN[1], '</td><td class="day name">', I18N._SDN[2], '</td>',
				'<td class="day name">', I18N._SDN[3], '</td><td class="day name">', I18N._SDN[4], '</td><td class="day name">', I18N._SDN[5], '</td><td class="day name weekend">', I18N._SDN[6], '</td>',
				'</tr></thead><tbody></tbody><tfoot><tr class="footrow">',
				'<td class="ttip"  colspan=7 navtype=301  >', I18N._Select, '</td></tr></tfoot></table></div>'].join( "" ),
//navtype 与 class=title的一致。 改为301
	timeTpl = ['<tr class=time><td class=time colspan=2 >', I18N._Time, '</td><td class=time colspan=3>',
				'<span class=hour   navtype="24" ttip="', I18N._Click, '">&nbsp;</span>',
				'<span class=colon>:</span><span class=minute navtype="60" ttip="', I18N._Click, '">&nbsp;</span>',
				'</td><td class=time colSpan=2>&nbsp;</td></tr>'].join( "" ) ,
	timeZoneTpl = ['<tr class="timezone"><td colspan=7 class="time_zone"><input type="text" name="timeZone_calendar" id="timeZone_calendar" service="LOOKUP2:LOOKUP_TIMEZONE"/></td></tr>'].join( "" );
	
	var config = {
			format : Ccay.Config.Format.date,   //默认显示格式

		//	showTime : false,		//是否显示时间 时分秒！

			showDate : true,

			wmindate : new Date( 1900, 0, 1 ),   //默认最小可选择时间

			wmaxdate : new Date( 9999, 11, 31 )  //默认最大可选择时间

		//	selectDate : null,  	//当前选择时间,
			
		//	initDate : false,  // 优先采用navDate 初始化，如果没有设置，则使用initDate，如果initDate也为空，则使用当前系统时间作为标准
			
		//	navDate : false,   //导航时间，如果有设置了导航时间，则以导航时间为标准初始化 时间选择控件的日期区域
			
		//	dblmonth : false,   //是否开启双月显示模式，值为 "prev"  显示当前月与前一个月  值为 "next"  显示当前月与下一月

		//	today : false //当前日期
			
	};
	
   var factory = Calendar.Factory = {
   		
		//根据input上的标签属性，初始化op的值
		initOp : function( calendar, op ){
    		var input = calendar.dom, format = input.attr( "format" ) || op.format;
    		
    		// datehm 与 datetime格式，需要显示时间选择区域（showTime）
    		if( format === "datehm" || format === "datetime" || (typeof format == "string" && format.indexOf("hh:mm")!=-1) ){
    			op.showTime = true;
    		}
    		
    		//指定showDate参数，用于控制时间选择控件是否显示 日期选择区域（showDate）
			if( input.attr( "showDate" ) === "false"  ){
				op.showDate=false;
			}
			if(op.showSecond ||  input.attr( "showSecond" ) || (typeof format == "string" && format.indexOf("hh:mm:ss")!=-1)){
				op.showSeconds = true;
			}
			
    		//为了兼容以前版本，如果不指定showSecond，datetime 格式 默认不显示秒，
    		if( format === "datetime" &&  !op.showSeconds){
    			format =  Ccay.Config.Format.datehm;
    		}
    		
    		if(input.attr("timezone") === "true"){
    			op.showTimeZone = true;
    		}
    		
    		if(input.attr("timezoneop") === "true"){
    			op.timezoneop = true;
    		}
    		
			//支持系统默认时间格式 date datehm datetime 或 自定义的格式
    		format = Ccay.Config.Format[ format ] || format;
			
			op.format = format;
			
			op.dblmonth = input.attr( "dblmonth" ) || op.dblmonth;
			
			var wmindate =  input.attr( "wmindate" ) || op.wmindate , wmaxdate =  input.attr( "wmaxdate" ) ||  op.wmaxdate;
			op.wmindate = wmindate && Calendar.Helper.copyDate( wmindate ) || config.wmindate; 
			
			op.wmaxdate = wmaxdate && Calendar.Helper.copyDate( wmaxdate )|| config.wmaxdate; 
			
			if(undefined != input.attr( "defaultdate" )&& input.attr( "defaultdate" ).length >= 8 && input.attr( "defaultdate" ).validDate(op.format) == true ){
				op.today =input.attr( "defaultdate" ).toDate().getUTCTime();
				op.isDefaultDate = true;
			}else{
				op.today =  Calendar.Helper.copyDate( new Date().getUTCTime());
			}
			
			if(input.attr("maxGap")){
    			 var maxGap = input.attr("maxGap"),
    			 	 compareTo = input.attr("compareTo");
    			 if(!isNaN(maxGap) && compareTo){
    			 	var compareTo_time = $(compareTo).ccayGetValue();
    			 	compareTo_time && ( op.wmaxdate = compareTo_time.toDate().addMonth(maxGap*1) );
    			 }
    			 
    		}
    		
			op.initDate = input.val().toDate(format);
		}
	}
	//结构构造器
    factory.Builder = {
    	
        buildPopup : function ( calendar, op ) {
			this.buildPopupPanel( calendar, op );
			this.buildDateArea( calendar, op );
			this.buildTimeArea( calendar, op );
			this.buildTimeZoneArea( calendar, op );
        },
        
		/** 生成日期选择区域  */
		buildDateArea : function( calendar, op ){
			//popuper 为弹出的时间选择层， input为 时间选择输入控件， value 为 时间选择输入控件的值 
			var popuper = calendar.getPopup(), input = calendar.dom, selDate = op.navDate || op.initDate, value = calendar.dom.val();
		
			op.navDate = null; 
			
			//清空状态与表格内容
			popuper.find( "tbody" ).empty();
			
			popuper.find( "table.second" ).remove();
			
			//得到需要展示的月份标准，如果没有专递selectDate，就按照当前日期展示
			if(!selDate &&  value.length >= 8 && value.validDate(op.format) !== true ){ 
				op.selectDate = selDate = op.today;
			}else{
				op.selectDate = selDate = selDate || value && value.toDate( op.format ) || op.today;
			}
			
			//初始化时间，为允许选择的时间范围之外，则将最大值或最小值作为依照生成他在弹出层
			if( !Calendar.Helper.inSelectRange( op, selDate ) ){
				op.selectDate = selDate = selDate > op.wmaxdate ? op.wmaxdate  : op.wmindate;
			}
			//在table内生成具体一个月的日期表格
			this.buildMonthForTable( popuper.find( "table.current" ), selDate, op );
			
			//如果是双月模式，则再添加一个日期显示table
			if( op.dblmonth ){
			
				var secondMonth = $( popuper.find( "table.current" ).parent().html() ).addClass( "second" ).removeClass( "current" );
				if( op.dblmonth == "prev" ){
					popuper.addClass( "dblmonth" ).find( "table" ).before( secondMonth.addClass( "prev" ) );
				}else{
					popuper.addClass( "dblmonth" ).find( "table" ).after( secondMonth.addClass( "next" ) );
				}
				var difM = ( op.dblmonth == "prev" ) ? -1 : 1; //得到月差异值
				
				var senondNavDate = new Date( selDate.getFullYear(), selDate.getMonth() + difM , 1 );
				
				//在table内生成具体一个月的日期表格
				this.buildMonthForTable( popuper.find( "table.second" ), senondNavDate, op );
				
			}else{
				popuper.removeClass( "dblmonth" );
			}
		
		},
		
		/** 生成时间选择区域  */
		buildTimeArea :function( calendar, op ){
			var popuper = calendar.getPopup();
			
			if( op.showTime || op.showSecond ){
				if( popuper.find( "tr.time" ).length == 0 ){
					var utcDate = op.initDate || ( new Date().getUTCTime());
					if(op.isDefaultDate){
						utcDate = op.today;
					}
					popuper.find( "tbody" ).append( $( timeTpl ) );
					this.buildInputTime(calendar,op,utcDate);
				}
			}else{
				popuper.find( "tr.time" ).hide();
			}
		},
		/** 创建时分秒区域 */
		buildInputTime:function(calendar,op,utcDate){
			var popuper = calendar.getPopup();
			var input = calendar.dom;
			function createInputTime(domIndex){
			var timespinner = $("#ccay_timespinner_input_{0}".formatValue(domIndex));
			var start = 0,ds=[utcDate.getHours(),utcDate.getMinutes()];
			op.showSeconds && ds.push(utcDate.getSeconds());
			function getTime(time){
				return time<10?"0"+time:time;
			}
			function setTime(time){				
				if(start>=6 && start<=8 && op.showSeconds){
					ds[2] += time;
					ds[2]>59 && (ds[2]=0);
					ds[2]<0 && (ds[2]=59);
				}else if(start>=3 && start<=5){
					ds[1] += time;
					ds[1]>59 && (ds[1]=0);
					ds[1]<0 && (ds[1]=59);
				}else{
					ds[0] += time;
					ds[0]>23 && (ds[0]=0);
					ds[0]<0 && (ds[0]=23);
				}
				var nds = [];
				$.each(ds,function(i,d){
					nds.push(getTime(d));
				});
				timespinner.val(nds.join(":"));				
			}
			setTime(0);
			function getRange(start){
				if(start>=6 && start<=8){
					return [6,8];
				}else if(start>=3 && start<=5){
					return [3,5];
				}else{
					return [0,2];
				}
			}
			function getStart(dom){
				if (typeof dom.selectionStart == "number") {
					start = dom.selectionStart;
				} else {
					if (dom.createTextRange) {
						var cTR = dom.createTextRange();
						var s = document.selection.createRange();
						s.setEndPoint("StartToStart", cTR);
						start = s.text.length;
					}
				}
				return start;
			}
			function setTextRange(dom,start){
				var range = getRange(start);
				if (dom.setSelectionRange) {
					dom.setSelectionRange(range[0],range[1]); 
				} else {
					if (dom.createTextRange) {
						var s = dom.createTextRange();
						s.collapse();
						s.moveEnd("character", range[1]);
						s.moveStart("character", range[0]);
						s.select();
					}
				}
				timespinner.focus();
			}
			   timespinner.parent().bind("click mousedown mouseup",function(e){
				 e.stopPropagation();
			   }).on("mouseover",function () {
				   input.data("ctr_locked", true);
				}).on("mouseout",function () {
					input.data("ctr_locked", false);
				});
			timespinner.bind("click",function(){
				start = getStart(this);
				setTextRange(this,start);
			}).bind("blur",function(){
				var regStr = op.showSeconds ? "^([0-9]{2}):([0-9]{2}):([0-9]{2})$" : "^([0-9]{2}):([0-9]{2})$";
				var reg = new RegExp(regStr);
				var value = $(this).val();
				if(reg.test(value)){
					var matchs = value.match(reg);
					matchs.splice(0,1);
					var isMatch = true,vl=[];
					for(var i=0;len=matchs.length,i<len;i++){
						var mv = parseInt(matchs[i],10);
						vl.push(mv);
						if((i==0 && mv>23) || (i>0 && mv>59)){
							isMatch = false;
						}
					}
					isMatch && (ds = vl);
				}
				setTime(0);
				$(this).find("input").focus();
			}).bind("keydown keyup",function(e){
				e.stopPropagation();
			});
			$("#ccay_timespinner_up_{0}".formatValue(domIndex)).click(function(){
				setTime(1);
				setTextRange(timespinner[0],start);
			});
			$("#ccay_timespinner_down_{0}".formatValue(domIndex)).click(function(){
				setTime(-1);
				setTextRange(timespinner[0],start);
			});
			}
			popuper.find("tr.time").each(function(i){
				$(this).children(":eq(1)").html('<div class="timespinner"><input type="text" id="ccay_timespinner_input_{0}" /><span class="timespinner-arrow"><i class="up" id="ccay_timespinner_up_{0}"></i><i class="down" id="ccay_timespinner_down_{0}"></i> </span></div>'.formatValue(i));
				createInputTime(i);
			});
		},
		buildTimeZoneArea : function( calendar, op ){
			var popuper = calendar.getPopup();
			if( op.showTimeZone){
				if( popuper.find( "tr.timezone" ).length == 0 ){
					popuper.find( "tbody" ).append( $( timeZoneTpl ) );
					var curDemo = $("#timeZone_calendar");
					curDemo.ccayCombobox({
						fnSelected : function(value, text,oldValue, item,selector){
							
							if(value){
								var timezone = Ccay.Personalized.global.common.timeZone ,
									valueSubStr = value.substring(3,value.length);
								timezone = timezone.substring(3,timezone.length);
									
								if(value !== oldValue){
									//
									if(!op.timezoneop && valueSubStr !== timezone){
										Ccay.Personalized._settings.get("global").common.timeZone = value;
										Ccay.Personalized.saveItem({settingKey : "global", settingContent : JSON.stringify(Ccay.Personalized._settings.get("global"))}, function(){
											Ccay.Personalized.init();
											Calendar.Helper.reInitPopup(value,timezone, calendar, op);
										});
									}else if(op.timezoneop &&  value !== op.curTimeZone){
										op.curTimeZone = value;
										op.initDate = new Date();
										Calendar.Helper.reInitPopup(value,"+8" , calendar, op);
									}
								}
							}
						}
					});
					curDemo.ccaySetValue(op.curTimeZone || Ccay.Personalized.global.common.timeZone);
				}
			}else{
				popuper.find( "tr.timezone" ).hide();
			}
		},
		/** 在指定table中生成指定月份的日期表格  */
		buildMonthForTable:function( table, targetDate, op){
			var tbody = table.find( "tbody" );
			//算出需要展示的月份的最大的日期time
			var currMaxTime = new Date( targetDate.getFullYear(), targetDate.getMonth()+1, 0 ).getTime();
			//算出需要展示的月份的最小的日期time
			var currMinTime = new Date( targetDate.getFullYear(), targetDate.getMonth(), 1 ).getTime();
			//得到当前展示月份第一天是星期几
			var currMinTimeDay=new Date( currMinTime ).getDay(); 
			
			//填充head中当前 与年份
			table.find( "thead td.title" ).text( currLang == "zh_CN" ? targetDate.format( "yyyy 年  MM 月" ) : I18N._MN[ targetDate.getMonth() ] + "," + targetDate.getFullYear() );
			
			//生成body实体，日期选择内容 bodyHtmls: 生成html的容器, firstRow : 生成第一行标示, dayIndex : 日期标识， caldate : 当前生成的日期
			var bodyHtmls = [], firstRow = true, dayIndex = 1, caldate = currMinTime;
		
			// 一个月最多跨度为六个星期，因此循环按六行输出
			for( var i = 0; i < 6; i++ ){
				
				bodyHtmls.push( "<tr class=daysrow>" ); //一行开始标签
				
				//每一行为一个星期，每个星期7天，循环7次输出具体内容
				for( var j = 0; j <= 6;j++ ){
					//第二个判断（caldate - currMaxTime > 2000 * 60 * 60）是为了修复夏令时 时间拨转情况
					if( firstRow && j < currMinTimeDay || caldate - currMaxTime > 60 * 60 * 1000){ 
						//非本月的日期数据，td  不显示具体内容。（第一行和末尾一行，都可能有非本月的的数据）
						bodyHtmls.push( '<TD class="disabled"  pos="{0}" class="day">&nbsp;</TD>'.formatValue( j ) );
					}else if( !Calendar.Helper.inSelectRange( op, caldate ) ){
						//不在选择范围内的日期，添加disabled 样式，不能选择
						bodyHtmls.push( '<TD class="day disabled" disabled  pos="{0}" caldate={1}>{2}</TD>'.formatValue( j, caldate, dayIndex ++ ) );
						caldate += 24 * 60 * 60 * 1000; //输出一个日期后，当前日期加上一天，用于下次循环输出
					}else{
						//周一周五 与周末 样式分别设置
						var strClass = j < 1 || j > 5 ? "day valid weekend" : "day valid";
						var dif = Calendar.Helper.copyDate(op.selectDate).getTime() - caldate;
						if(dif <= 3600 * 1000 && dif >  3600 * (-1000)){
							strClass += " selected"; //默认选中当前初始化的目标日期（添加默认选择样式）
						}
						if( caldate == op.today.getTime() ){
							strClass += " today"; //为当前系统时间添加高亮显示样式
						}
						//正常可选择的数据td生成
						bodyHtmls.push( '<TD class="{0}" ttip="_" pos="{1}" caldate={2}>{3}</TD>'.formatValue( strClass, j, caldate, dayIndex ++ ) );
						caldate += 24 * 60 * 60 * 1000; //输出一个日期后，当前日期加上一天，用于下次循环输出
					}
				}
				firstRow=false;
				bodyHtmls.push( "</tr>" ); //一行结束标签
				if( caldate -  currMaxTime >  60 * 60 * 1000 && !op.dblmonth ){
					break;
				}
					
			}
			tbody.html( bodyHtmls.join( "" ) );
		},
		
		/**  创建时间选择弹出面板，仅会初始化一次，所有时间控件公用一个弹出面板  */
		buildPopupPanel : function( calendar, op ){
			if( templ ){
				popuper = $( templ ).appendTo( $( document.body ) ).focusout(function(e){
					var poper = $(this);
					if(poper.attr("active" ) === "false" ){
						if( !(op.showTimeZone && $("#timeZone_calendar_ddl:visible").length)){
							poper.hide();
						}
					}
				});
				templ = null;//清空变量
			}
			//将日期输入框与日期弹出选择框通过 一个编号建立一个联系
			calendar.getPopup().attr( "for", op.popupId )
		}
    };

    factory.EventBinder = {
        init: function ( calendar, op ) {
        	/** 绑定文本框的 click 事件*/
        	this.bindClick( calendar, op );
        	
        	/** 绑定文本框的 blur 事件*/
        	this.bindBlur( calendar, op );
        	
        	/** 绑定文本框的 keydown 事件*/
        	this.bindKeyDown( calendar, op );
        },
        
        
		/** 绑定文本框的 click 事件*/
		bindClick : function( calendar, op ){
			 calendar.dom.bind( "click", function( e ){
			 	calendar.getPopup().find( "table.current" ).find("tr.daynames").show();
				//如果当前是打开着的，点击则关闭弹出选择层，否则打开重建
				calendar.isPopup() ? calendar.hidePopup() :  Calendar.Helper.showPopup( calendar, op );
				e.stopPropagation();
			} );

		},
		
		/** 绑定文本框的 blur 事件*/
		bindBlur : function( calendar, op ){ 
			 calendar.dom.bind( "focusout", function( e ){
			 	if( !(op.showTimeZone && $("#timeZone_calendar_ddl:visible").length)){
					//如果当前是打开着的，点击则关闭弹出选择层，否则打开重建
					if( calendar.isPopup() &&  calendar.getPopup().attr( "active" ) === "false"){
						calendar.hidePopup();
					}
					var value = $.trim(this.value);
					var format = !$(this).attr("format") || !Ccay.Config.Format[$(this).attr("format")] ? op.format : null;
					if(value && value.validDate(format,op.showTime)){ 
						 this.value = value.toDate(format).format(op.format);
					}
			 	}
			} );
			
		},
		
		/** 绑定文本框的keydown事件*/
		bindKeyDown : function( calendar, op ){
        	calendar.dom.bind( "keydown", function( e ){
        		if( calendar.isPopup()){
					switch( e.keyCode ){
						case 37: ;//key left
						case 38: ;//key up
						case 39: ;//key right
						case 40: $("#selectMonth").length ?Calendar.Helper.move( calendar, e.keyCode , e ) : factory.EventBinder.move( calendar, e.keyCode , e ); break;//key down
						
						case 32: Calendar.Helper.goToday( calendar, true, e ); break//space
						
						case 27: calendar.hidePopup(); break;//esc
						
						case 13: Calendar.Helper.selected( calendar ); break;//enter
						
						case 17: break;//ctrl 17 或 e.ctrlKey
						
						default :calendar.hidePopup(); return true;
					}
					return false;
        		}
        	} )
        	//数字日期自动带-
        	calendar.dom.bind( "focusout", function( e ){
        		var date = calendar.dom.val();
        		if(""!= date && date.length== 8 &&NaN!=parseInt(date)){
        			var y = date.substring(0,4);
        			var m = date.substring(4,6);
        			var s = date.substring(6,date.length);
        			date = y+"-"+m+"-"+s;
        			calendar.dom.val(date);
        		}
        	})
		},
		
		initPopup : function( calendar, op ){
			
			/**  时间弹出层 click选择操作事件绑定 */
			this.bindPopuerClick( calendar, op );
			
			/**  时间弹出层 鼠标效果事件绑定 */
			this.bindPopuerMouseEvent( calendar, op );
		},
		
		/**  时间弹出层 click选择操作事件绑定 */
        bindPopuerClick: function( calendar, op ){
        	
        	var popuper = calendar.getPopup();
			
        	popuper.bind( "click", false );
        	
        	popuper.undelegate( "td.time_zone", "click" ).delegate( "td.time_zone", "click", function( e ){
        		$(this).find("input").focus();
        	});
			//注册单元格点击事件
			popuper.undelegate( "td[class!='time_zone']", "click" ).delegate( "td[class!='time_zone']", "click", function( e ){
				e.stopPropagation();
				var td = $( this );
				//无效的日期，不处理点击事件
				if( td.hasClass( "disabled" ) ){
					
					calendar.dom.focus();
					return; 
				}
				if(op.dblmonth && td.hasClass("title")){
					return ;
				}
				
				//target 为触发事件源， navtype 为触发的功能类型编号
				var target = $.getEventTarget(e), navtype = td.attr( "navtype" ) || target.attr( "navtype" );
				
				var time,str,selectMonLength = $("#selectMonth").length;
				//判断 是否为 月份选择页面
				if(!selectMonLength){
					//得到点击td 的具体时间
					time = popuper.find( "tbody td.selected" ).attr( "caldate" );
					time = !isNaN( time ) ? time * 1 : 0; //如果是数字格式，则转换成number类型
				}else {
					str = popuper.find( "td.title" ).text();
					if(currLang == "en_US"){
						var currMonth = str.split(",")[0] , i=0 , currYear = str.split(",")[1];
						while(i<I18N._MN.length){
							if(I18N._MN[i] == currMonth){
							   //修复在选择月份的时候出现undefined,NaN。
								currMonth = i < 10 ? ("0"+i) : i+1;
								break;
							}
							i++;
						}
						time = new Date(currYear,currMonth).getTime();
					}else 
						time = new Date(str.substr(0,4)*1,str.substr(8,2)*1-1).getTime();
				}
				var navDate = new Date( time || op.selectDate.getTime() );//得到当前选择时间或默认选中时间
				
				// 如果有触发导航功能，则按照导航编号，做具体处理
				if( navtype ){
					switch( navtype * 1 ){
						
						case 200: calendar.hidePopup(); return; //编号200 : 点击关闭按钮
						
						case 300: Calendar.Helper.getAllMonth(calendar); break;//显示月份选择
						
						case  0 : Calendar.Helper.goToday( calendar, false, e ); break; //编号0， 点击 today
						
						case -1 : navDate = navDate.addMonth( -1 ); break;//上一个月
						
						case  1 : navDate = navDate.addMonth( 1 ) ; break;//下一个月
						
						case -2 : navDate.setFullYear( navDate.getFullYear() - 1 ); break;//上一年
						
						case  2 : navDate.setFullYear( navDate.getFullYear() + 1 ); break;//下一年
						
						case 24 : popuper.find( "span.hour" ).text( Calendar.Helper.plusTime( target.text(), 24, !e.ctrlKey ) );break; //小时
						
						case 60 : popuper.find( "span.minute" ).text( Calendar.Helper.plusTime( target.text(), 60, !e.ctrlKey ) );break; //分钟
					}
					//如果只操作了时间，无需翻页刷新所有日期
					if(navtype == 0){
						
					}else if( navtype == 24 || navtype == 60 ){
						Calendar.Helper.setValue( calendar, navDate );
					}else if(navtype!=300 && (Calendar.Helper.inSelectRange( op, new Date( navDate.getFullYear(), navDate.getMonth() + 1 , 0 ) ) 
						||  Calendar.Helper.inSelectRange( op, new Date( navDate.getFullYear(), navDate.getMonth(), 1 ) ) )){
							
						op.navDate = navDate;
						//刷新日期选择框，重新按照新的导航时间navDate 生成 选择面板
						
						//如果是选择月份，则直接选中月份，不重新加载面板显示具体日期
						if(selectMonLength){
							Calendar.Helper.getAllMonth(calendar);
							$("#selectMonth td.selected").removeClass("selected");
							$("#selectMonth td:eq("+op.navDate.getMonth()+")").addClass("selected");
							var currerDate = new Date(op.navDate.getTime());
							popuper.find( "thead td.title" ).text( currLang == "zh_CN" ? currerDate.format( "yyyy 年  MM 月" ) : I18N._MN[ currerDate.getMonth() ] + "," + currerDate.getFullYear() );
						}else{
							factory.Builder.buildPopup( calendar, op );
						}
						
						if( op.showDate == false ){
							Calendar.Helper.setValue( calendar, navDate )
						}
					}
				}else if( td.hasClass( "day" ) ){
					// 直接触发了日期单元格的点击时间，则得到点击的日期时间值，并触发选择操作
					var selected = td.attr( "caldate" );
					if(selectMonLength){
						var time1;
						str = popuper.find( "table.current" ).find("td.ttip").html();
						if(currLang == "en_US"){
							var currMonth = str.split(",")[1] , i=0 , currYear = str.split(",")[0];
							while(i<I18N._SMN.length){
								if(I18N._SMN[i] == currMonth){
									currMonth = i < 10 ? ("0"+i) : i;
									break;
								}
								i++;
							}
							time1 = new Date(currYear,currMonth).getTime();
						}else 
							time1 = new Date(str.substr(0,4)*1,str.substr(7,2)*1-1).getTime();
						
						if(op.navDate == null || (op.navDate.toString() === op.selectDate.toString()) || time !== time1){
							navDate = new Date( time1 );//得到当前选择时间
							op.navDate = navDate;
						}
					}
					if( selected ){
						Calendar.Helper.selected( calendar, td );
					}
				}
				calendar.dom.focus();
			} );
        	
        },

		
		/** 通过方向键移动选择日期 具体实现*/
		move : function( calendar, k, e ){
			var popuper = calendar.getPopup(), op = calendar.op, currSelectedTd = popuper.find( "tbody td.selected" );
			
			if( currSelectedTd.length > 0 ){
				var moveToDate=new Date( currSelectedTd.attr( "caldate" )*1 );//得到当前热点日期，并算出需要移动到的日期
				if( k==37 ){
					moveToDate.setDate( moveToDate.getDate() -1 ); //加一天
				}else if( k==39 ){
					moveToDate.setDate( moveToDate.getDate() + 1 ); //减一天
				}else if( k==38 ){
					_stopDefasultEvent( e );  //阻止浏览器默认事件（如果页面有上下滚动条，不阻止事件，会导致页面滚动）
					moveToDate.setDate( moveToDate.getDate() - 7 ); //减一个星期
				}else if( k==40 ){
					_stopDefasultEvent( e ); //阻止浏览器默认事件（如果页面有上下滚动条，不阻止事件，会导致页面滚动）
					moveToDate.setDate( moveToDate.getDate() + 7 ); //加一个星期
				}
				//判断移动后的时间是否是可选范围，不是可选返回则直接返回，无需要移动
				if( Calendar.Helper.inSelectRange( op, moveToDate ) ){
					//通过找td，判断是否在本月移动
					var moveToTd= popuper.find( "tbody td[caldate='" + moveToDate.getTime() + "']" );
					//如果能找到，说明是在本月移动，直接替换样式
					if( moveToTd.length>0 ){
						currSelectedTd.removeClass( "selected" );
						moveToTd.addClass( "selected" );
					}else{
						//非本月内，则需要重新生成日期选择区域，
						op.navDate=moveToDate;
						factory.Builder.buildPopup( calendar, op );
					}
				}
			
			}
			
		},
		
		/**  时间弹出层 鼠标效果实现 */
		bindPopuerMouseEvent:function( calendar, op ){
			var popuper = calendar.getPopup();
			//取消日期选择框事件的冒泡
			popuper.bind( "mousedown",false );
			//注册事件

			//添加鼠标移入 事件效果，给td变色
			popuper.delegate( "td", "mouseover", function( e ){
				var target = $.getEventTarget(e), td = $( this ),currLength = $("#selectMonth").length;
				if( td.hasClass( "button" ) ){
					
					td.addClass( "active" );
					
					popuper.find( "td.ttip" ).text( td.attr( "ttip" ) || (currLength ? I18N._SelectMonth : I18N._Select ));
					
				}else if( td.hasClass( "valid" ) ){
					var d= new Date( td.attr( "caldate" ) * 1 + 1000 * 60 * 60);
					var ttip = currLang == "zh_CN" ? d.format( "yyyy 年MM 月dd 日" ) : I18N._SDN[ d.getDay() ] + "," + I18N._SMN[ d.getMonth() ] + " " + td.text();
					
					//选择月份
					if(currLength){
						var str = popuper.find( "td.title" ).text(),currYear = currLang == "zh_CN" ? str.substr(0,4) : str.split(",")[1],titleTime;
						ttip = currLang == "zh_CN" ? currYear+" 年"+d.format( " MM 月" ) : currYear + "," + I18N._SMN[ d.getMonth() ];
					
						if(currLang == "en_US"){
							var currMonth = str.split(",")[0] , i=1 , currYear = str.split(",")[1];
							while(i<I18N._MN.length){
								if(I18N._MN[i-1] == currMonth){
									currMonth = i < 10 ? ("0"+i) : i;
									break;
								}
								i++;
							}
							titleTime = new Date(currYear,currMonth);
						}else 
							titleTime = new Date(str.substr(0,4)*1,str.substr(8,2)*1-1);
							
						var navDate = new Date( titleTime.getTime() || op.selectDate.getTime() );//得到当前选择时间或默认选中时间
						navDate =navDate.addMonth(d.getMonth() - titleTime.getMonth());
						op.navDate = navDate;
					}
					
					popuper.find( "td.ttip" ).text( ttip );
					
					td.addClass( "hilite" );
				}else if( target.hasClass( "hour" ) || target.hasClass( "minute" ) ){
					target.addClass( "hilite" );
					
					popuper.find( "td.ttip" ).text( target.attr( "ttip" ) );
				}
			} );
			//添加鼠标移入 事件效果，给td还原颜色
			popuper.delegate( "td", "mouseout", function( e ){
				var target = $.getEventTarget(e),td = $( this );
				
				if( td.hasClass( "button" ) ){
					td.removeClass( "active" );
				}else if( td.hasClass( "valid" ) ){
					td.removeClass( "hilite" );
				}else if( target.hasClass( "hour" ) || target.hasClass( "minute" ) ){
					target.removeClass( "hilite" );
				}
				popuper.find( "td.ttip" ).text($("#selectMonth").length ? I18N._SelectMonth : I18N._Select);
			} );
			
			popuper.bind( "mouseover", function(){
				$(this).attr( "active", true);
			} );
			
			popuper.bind( "mouseout", function(){
				$(this).attr( "active", false);
			} );
			//该事件只绑定一次，第一次绑定后，清空方法
			this.bindPopuerMouseEvent = function(){};		
		}
    }
    
    
	Calendar.Helper = {
		
		/** @description 一个日期对象值，创建一个新的对象，并且将 时分秒清零 */
		copyDate : function( date ){
			var date = Ccay.Format.toDate( date );
			return new Date( date.getFullYear(), date.getMonth(), date.getDate() );
		},
		
		/** @description 判断日期是否是可选范围之类 （wmaxdate wmindate）*/
		inSelectRange:function( op, date ){
			var dateNoTime = this.copyDate( date );
			if( dateNoTime > op.wmaxdate || dateNoTime < op.wmindate ){
				return false
			}
			return true;
		},
		
		/**  小时 分钟 计算
		 * @param {number} number，当前小时或分钟数字
		 * @param {nubmer} max，最大值取模，小时用24取模，分钟用 60取模
		 * @plus {boolean} 是否是是加1，为false，则减1
		 */
		plusTime:function( number,max,isPlus ){
			number = number * 1;
			if( isPlus ){
				number ++ ;
				number = number % max;
			}else{
				number --;
				number = ( max + number ) % max;
			}
			return ( "" + number ).fillChar( 2 );
		},
		
		/** 点击选择一个日期 */
		selected : function( calendar, selTd ){
			var popuper = calendar.getPopup(),op = calendar.op;
			
			if($("#selectMonth").length && op.showDate){
				popuper.find("tr.daynames").show();
				factory.Builder.buildPopup( calendar, op );
			}else{
				var selectdTd = selTd || popuper.find( "tbody td.selected" );
				//解绝夏令时结束后，时间转拨，会小一个时辰的问题
				var date =  Calendar.Helper.copyDate(new Date( selectdTd.attr( "caldate" ) * 1 + 1000 * 60 * 60 ));
				this.setValue( calendar, date);
				calendar.hidePopup();
			}
		},
		
		/**  设置文本框的值 */
		setValue : function( calendar,value ){
			var input = calendar.dom, op = calendar.op, popuper = calendar.getPopup();
			if( op.showTime ){
				var timeValue = $("#ccay_timespinner_input_0").val();
				var timeArray = timeValue ? timeValue.split(":") : [0,0,0];
				value.setHours(parseInt(timeArray[0],10));
				value.setMinutes(parseInt(timeArray[1],10));
				//当有值时，保存秒数不变，否则为当前秒数。
				op.showSeconds && value.setSeconds(parseInt(timeArray[2],10));
			}
			
			if( Calendar.Helper.inSelectRange( op, value ) ){
				 
				input.val( value.format( op.format ) );
				//日期类型数据处理
//				
				value = value.getUTCTime("+8",op.curTimeZone);
				if(op.timezoneop){
					var bool = ( input.attr("showDate")=="false" || input.attr("datatype") == "string" );
					if( !op.format || ( op.format && bool ) ){
						input.data("value" , value.format( op.format ) );
					}else if(op.format && !bool){
						input.data("value" , value.toDate(format) );
					}
				}
				
				if( typeof input.valid == "function" ){
					input.valid();
				} 
				input.change();
			}
		},
		
		goToday : function( calendar, isSpace, e ){
			
			var op = calendar.op,today = op.today.getTime();
			if(Calendar.Helper.inSelectRange( op, today )){
				this.setValue( calendar, Calendar.Helper.copyDate(new Date( today * 1 + 1000 * 60 * 60 )));
				calendar.hidePopup();
			}
		},
		
		showPopup : function( calendar, op ){
			
			factory.initOp( calendar, op );
			
			factory.Builder.buildPopup( calendar, op );
			
			factory.EventBinder.initPopup( calendar, op );
			
			calendar.showPopup();
		},
		//
		reInitPopup:function(value,timezone, calendar, op){
			op.today = Calendar.Helper.copyDate( new Date().getUTCTime(value.substring(3,value.length)) ,  timezone);
			
			if(op.initDate){
				var curValue = op.initDate;
				
				op.initDate = op.initDate.getUTCTime(value.substring(3,value.length) ,  timezone);
				calendar.dom.val(op.initDate.format("yyyy-MM-dd hh:mm"));
				
				if(op.timezoneop){
					var bool = ( calendar.dom.attr("showDate")=="false" || calendar.dom.attr("datatype") == "string" );
					if( !op.format || ( op.format && bool ) ){
						calendar.dom.data("value" , curValue.format( op.format ) );
					}else if(op.format && !bool){
						calendar.dom.data("value" , curValue );
					}
				}
			}
			
			factory.Builder.buildPopup( calendar, op );
			calendar.getPopup().show();
			calendar.dom.focus();
		},
		
		//显示所有月份，月份选择
		getAllMonth : function(calendar){
			var popuper = calendar.getPopup(),table = popuper.find( "table.current" ),tbody = table.find( "tbody" );
			var op = calendar.op,selDate=op.navDate||op.selectDate,year=selDate.getFullYear();
			
			table.find("tr.daynames").hide();
			table.find("td.ttip").text(I18N._SelectMonth);
			
			var htmlArray = "<tr rowspan='4'><td colspan='7'><table id='selectMonth'>" +
					"<tr class='daysrow'>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,0,1)).getTime())+I18N._SMN[0]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,1,1)).getTime())+I18N._SMN[1]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,2,1)).getTime())+I18N._SMN[2]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,3,1)).getTime())+I18N._SMN[3]+"</td>" +
					"</tr>" +
					"<tr class='daysrow'>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,4,1)).getTime())+I18N._SMN[4]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,5,1)).getTime())+I18N._SMN[5]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,6,1)).getTime())+I18N._SMN[6]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,7,1)).getTime())+I18N._SMN[7]+"</td>" +
					"</tr>" +
					"<tr class='daysrow'>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,8,1)).getTime())+I18N._SMN[8]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,9,1)).getTime())+I18N._SMN[9]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,10,1)).getTime())+I18N._SMN[10]+"</td>" +
						"<td class='day valid' caldate='{0}'>".format((new Date(year,11,1)).getTime())+I18N._SMN[11]+"</td>" +
					"</tr></table></td></tr>";
			tbody.html(htmlArray).show();
			//修复日期控件 月份 范围  不置灰 
			if(op.wmindate){
				var minDate = new Date(op.wmindate);
				var minYear = minDate.getFullYear();
				var minMonth = minDate.getMonth();
				if(minYear == year){
					$("#selectMonth td:lt("+minMonth+")").addClass("disabled");
				}
			}
			if(op.wmaxdate){
				var maxDate = new Date(op.wmaxdate);
				var maxYear = maxDate.getFullYear();
				var maxMonth = maxDate.getMonth();
				if(maxYear == year){
					$("#selectMonth td:gt("+maxMonth+")").addClass("disabled");
				}
			}
			var taArray = $("#selectMonth td");
			taArray.css("text-align","center");
			
			//突出当前月
			$(taArray.get(calendar.op.today.getMonth())).addClass("today");
			$(taArray.get(calendar.op.selectDate.getMonth())).addClass("selected");
			
		},
		//月份选择的键盘事件
		move : function(calendar, k, e){
			var popuper = calendar.getPopup(), op = calendar.op, currSelectedTd = popuper.find( "tbody td.selected" );
			
			if( currSelectedTd.length > 0 ){
				var str = popuper.find( "td.title" ).text(), time ,navDate;
				if(currLang == "en_US"){
					var currMonth = str.split(",")[0] , i=0 , currYear = str.split(",")[1];
					while(i<I18N._MN.length){
						if(I18N._MN[i] == currMonth){
							currMonth = i < 10 ? ("0"+i) : i;
							break;
						}
						i++;
					}
					time = new Date(currYear,currMonth).getTime();
				}else 
					time = new Date(str.substr(0,4)*1,str.substr(8,2)*1-1).getTime();
					navDate = new Date(time);
				
				if( k==37 ){//减一个月
					navDate = navDate.addMonth( -1 );
				}else if( k==39 ){//加一个月
					navDate = navDate.addMonth( 1 );
				}else if( k==38 ){//加四个月
					navDate = navDate.addMonth( -4 );
				}else if( k==40 ){//减四个月
					navDate = navDate.addMonth( 4 );
				}
				op.navDate = navDate;
				$("#selectMonth td.selected").removeClass("selected");
				$("#selectMonth td:eq("+op.navDate.getMonth()+")").addClass("selected");
				var currerDate = new Date(op.navDate.getTime());
				popuper.find( "thead td.title" ).text( currLang == "zh_CN" ? currerDate.format( "yyyy 年  MM 月" ) : I18N._MN[ currerDate.getMonth() ] + "," + currerDate.getFullYear() );
			}
		}
	};
	
	
    var manager = {
	    
	    getPopup : function(){
	    	 return $( "#ccay_calendar_div" );
	    },

		focus : function(){
			this.dom.focus();
		},
		
		hidePopup : function(){
			this.dom.removeData("ctr_locked",true);
			this.getPopup().hide();
			$("#timeZone_calendar_ddl").hide();
		},
		
		isPopup : function(){
			
			var popuper = this.getPopup();
			
			return (this.op.popupId == popuper.attr("for") && popuper.css( "display" ) != "none");
		},
		
		showPopup : function(){
			var op = this.op, popuper = this.getPopup(), input = this.dom;
			
			if( !op.showDate ){
				popuper.find( "tbody,tr.dayNames" ).hide();
				Calendar.Helper.getAllMonth(this);
			}else{
				popuper.find( "tbody,tr.dayNames" ).show();
			}
			popuper.css( "width" , op.dblmonth ? 430 : 215 );
			if(op.dblmonth){
				if(popuper.hasClass("dblmonth")){
					var currTd = popuper.find("table td.title");
					currTd.hasClass("button") && currTd.removeClass("button");
				}
			}else {
				popuper.find("table td.title").addClass("button");
			}
			Ccay.UI.popup( input, popuper, {top: input.height() + 4 }, true, true, null, true);
		}


	};

    var flow = {

		init : function( calendar, op ){
			
			op.popupId = $.newGuid( "CAL" );
			factory.initOp( calendar, op );
			calendar.dom.attr( "calendar", op.popupId );
		},

		bindEvent : function( calendar, op ){
			
			factory.EventBinder.init( calendar, op );
		}
	};

	var XCalendar = Ccay.UI.XControl( "XCalendar", flow, config, manager );
	
	 $.fn.calendar = function ( op ) {
	 	
	 	this.each( function(){
	 		var input = $( this );
	 		if(!input.attr("init")){
	 			input.attr("init", true);
	 			calendar = new XCalendar( input , op );
	 		}
	 	} );
	 	return this;

	}
	

} )( Ccay.UI.XCalendar );
//将接口添加到自动UI初始化集合中，加载页面ccayLoad 都会自动调用该处理器初始化UI
Ccay.UI.Renders.add(function(initCtrs, contenxt){
	initCtrs.filter(".ccay-calendar").ccayDatepicker();
});
